package com.zhss.dfs.server;

import com.alibaba.fastjson.JSONObject;
import com.zhss.dfs.server.model.LogDiskRecorder;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @program: filesystem
 * @description: 内存双缓冲
 * @author: Liu Weidong
 * @create: 2024-04-30 18:30
 **/
public class DoubleBuffer {

    /**
     * 单块editslog缓冲区的最大大小：默认是512字节
     */
    public static final Integer EDIT_LOG_BUFFER_LIMIT = 10 * 1024;
    /**
     * 是专门用来承载线程写入edits log
     */
    EditLogBuffer currentBuffer = new EditLogBuffer();
    /**
     * 专门用来将数据同步到磁盘中去的一块缓冲
     */
    EditLogBuffer syncBuffer = new EditLogBuffer();

    /**
     *  存储罗盘的日志文件 key为tixd集合  value文件路径
     */
    private List<LogDiskRecorder> logDiskRecorders = new ArrayList<>();

    /**
     *  写入editslog日志
     */
    ByteArrayOutputStream buffer = new ByteArrayOutputStream(EDIT_LOG_BUFFER_LIMIT * 2);

    Long lastTxid = 1L;

    Long maxTxid = 0L;



    public void addDiskRecorder(LogDiskRecorder logDiskRecorder) {
        logDiskRecorders.add(logDiskRecorder);
    }

    /**
     * 将edits log写到内存缓冲里去
     * @param log
     */
    public void write(EditLog log) throws IOException {
        maxTxid = log.getTxid();
        currentBuffer.write(log);
    }

    /**
     *  判断是否将缓存中数据刷入到磁盘中
     * @return
     */
    public boolean shouldSyncToDisk(){
        return currentBuffer.size() >= EDIT_LOG_BUFFER_LIMIT;
    }

    /**
     * 交换两块缓冲区，为了同步内存数据到磁盘做准备
     */
    public void setReadyToSync() {
        EditLogBuffer tmp = currentBuffer;
        currentBuffer = syncBuffer;
        syncBuffer = tmp;
    }


    /**
     * 将syncBuffer缓冲区中的数据刷入磁盘中
     */
    public void flush() throws Exception {
       syncBuffer.flush();
       syncBuffer.clear();
    }

    /**
     * 返回当前缓冲数据中的内容
     */
    public byte[] getCurrentBuffer(){
        return buffer.toByteArray();
    }

    public List<LogDiskRecorder> getDiskLogData(){
        return this.logDiskRecorders;
    }

    class EditLogBuffer{



        String logDir = "D://dfs//log//";

        /**
         * 将log写入缓冲区
         * @param editLog
         */
        public void write(EditLog editLog) throws IOException {
            JSONObject jsonObject = JSONObject.parseObject(editLog.getContent());
            jsonObject.put("txid", editLog.getTxid());
            buffer.write((jsonObject + "\n").getBytes(StandardCharsets.UTF_8));
            System.out.println("向缓存中写入一条数据：" + jsonObject.toJSONString() + " 缓冲区大小" + size());
        }

        public Integer size(){
            return buffer.size();
        }

        public void flush() throws Exception {
            byte[] bytes = buffer.toByteArray();
            ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
            RandomAccessFile accessFile = null;
            FileChannel fileChannel = null;
            // 进行数据落盘
            try {
                String logFilePath = logDir + lastTxid + "-" + maxTxid + ".log";
                accessFile = new RandomAccessFile(logFilePath, "rw");
                fileChannel = accessFile.getChannel();
                fileChannel.write(byteBuffer);
                fileChannel.force(true);
                LogDiskRecorder logDiskRecorder = new LogDiskRecorder(lastTxid, maxTxid, logFilePath);
                logDiskRecorders.add(logDiskRecorder);
                lastTxid = maxTxid + 1;
                System.out.println("缓存区的数据进行了一次刷盘处理。。。。。。。。。。");
            } finally {
                if (accessFile != null) {
                    accessFile.close();
                }
                if (fileChannel != null) {
                    fileChannel.close();
                }
            }
        }
        public void clear(){
            buffer.reset();
        }
    }
}
